<html>
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<head>
<title>Section 15.8.&nbsp; Semaphores</title>
<link rel="STYLESHEET" type="text/css" href="images/style.css">
<link rel="STYLESHEET" type="text/css" href="images/docsafari.css">
</head>
<body>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;"><a href="toc.html"><img src="images/team.gif" width="60" height="17" border="0" align="absmiddle"  alt="Team BBL"></a></div></td>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=ch15lev1sec7.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<a href=ch15lev1sec9.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
<br><table width="100%" border="0" cellspacing="0" cellpadding="0"><tr><td valign="top"><a name="ch15lev1sec8"></a>
<h3 class="docSection1Title">15.8. Semaphores</h3>
<p class="docText">A semaphore isn't a form of IPC similar to the others that we've described (pipes, FIFOs, and message queues). A semaphore is a counter used to provide access to a shared data object for multiple processes.</P>
<blockquote>
<p class="docText">The Single UNIX Specification includes an alternate set of semaphore interfaces in the semaphore option of its real-time extensions. We do not discuss these interfaces in this text.</P>
</blockquote>
<p class="docText">To obtain a shared resource, a process needs to do the following:</p>
<div style="font-weight:bold"><ol class="docList" type="1"><LI><div style="font-weight:normal"><p class="docList">Test the semaphore that controls the resource.</P></div></LI><li><div style="font-weight:normal"><p class="docList">If the value of the semaphore is positive, the process can use the resource. In this case, the process decrements the semaphore value by 1, indicating that it has used one unit of the resource.</P></div></LI><LI><div style="font-weight:normal"><p class="docList">Otherwise, if the value of the semaphore is 0, the process goes to sleep until the semaphore value is greater than 0. When the process wakes up, it returns to step 1.</p></div></LI></ol></div>
<p class="docText"><a name="idd1e115181"></a><a name="idd1e115184"></a><a name="idd1e115189"></a><a name="idd1e115194"></a><a name="idd1e115199"></a>When a process is done with a shared resource that is controlled by a semaphore, the semaphore value is incremented by 1. If any other processes are asleep, waiting for the semaphore, they are awakened.</p>
<p class="docText">To implement semaphores correctly, the test of a semaphore's value and the decrementing of this value must be an atomic operation. For this reason, semaphores are normally implemented inside the kernel.</P>
<p class="docText">A common form of semaphore is called a <span class="docEmphasis">binary semaphore</span>. It controls a single resource, and its value is initialized to 1. In general, however, a semaphore can be initialized to any positive value, with the value indicating how many units of the shared resource are available for sharing.</P>
<p class="docText">XSI semaphores are, unfortunately, more complicated than this. Three features contribute to this unnecessary complication.</P>
<div style="font-weight:bold"><ol class="docList" type="1"><li><div style="font-weight:normal"><p class="docList">A semaphore is not simply a single non-negative value. Instead, we have to define a semaphore as a set of one or more semaphore values. When we create a semaphore, we specify the number of values in the set.</P></div></LI><li><div style="font-weight:normal"><p class="docList">The creation of a semaphore (<tt>semget</tt>) is independent of its initialization (<tt>semctl</tt>). This is a fatal flaw, since we cannot atomically create a new semaphore set and initialize all the values in the set.</P></div></LI><li><div style="font-weight:normal"><p class="docList">Since all forms of XSI IPC remain in existence even when no process is using them, we have to worry about a program that terminates without releasing the semaphores it has been allocated. The <span class="docEmphasis">undo</span> feature that we describe later is supposed to handle this.</p></div></li></ol></div>
<p class="docText">The kernel maintains a <tt>semid_ds</tt> structure for each semaphore set:</p>

<pre>
   struct semid_ds {
     struct ipc_perm  sem_perm;  /* see Section 15.6.2 */
     unsigned short   sem_nsems; /* # of semaphores in set */
     time_t           sem_otime; /* last-semop() time */
     time_t           sem_ctime; /* last-change time */
     .
     .
     .
   };
</pre><BR>

<p class="docText">The Single UNIX Specification defines the fields shown, but implementations can define additional members in the <tt>semid_ds</tt> structure.</p>
<p class="docText">Each semaphore is represented by an anonymous structure containing at least the following members:</P>

<pre>
   struct {
     unsigned short  semval;   /* semaphore value, always &gt;= 0 */
     pid_t           sempid;   /* pid for last operation */
     unsigned short  semncnt;  /* # processes awaiting semval&gt;curval */
     unsigned short  semzcnt;  /* # processes awaiting semval==0 */
     .
     .
     .
   };
</pre><br>

<p class="docText"><a name="idd1e115266"></a><a name="idd1e115269"></a><a name="idd1e115274"></a><a name="idd1e115279"></a><a name="idd1e115282"></a><a name="idd1e115285"></a><a name="idd1e115288"></a><a name="idd1e115295"></a><a name="idd1e115302"></a><a name="idd1e115307"></a><a name="idd1e115312"></a><a class="docLink" href="#ch15fig28">Figure 15.28</a> lists the system limits (<a class="docLink" href="ch15lev1sec6.html#ch15lev2sec3">Section 15.6.3</a>) that affect semaphore sets.</P>
<a name="ch15fig28"></a><p><table cellspacing="0" class="allBorders" border="1" RULES="groups" cellpadding="5"><caption><h5 class="docTableTitle">Figure 15.28. System limits that affect semaphores</h5></caption><colgroup><col width="300"><col width="50"><col width="50"><col width="50"><col width="50"></colgroup><thead><tr><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="middle" rowspan="2"><p class="docText"><span class="docEmphRoman">Description</span></p></th><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="top" colspan="4"><p class="docText"><span class="docEmphRoman">Typical values</span></p></th></tr><tr><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="bottom"><p class="docText"><span class="docEmphRoman">FreeBSD 5.2.1</span></p></th><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="bottom"><p class="docText"><span class="docEmphRoman">Linux 2.4.22</span></p></th><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="bottom"><p class="docText"><span class="docEmphRoman">Mac OS X 10.3</span></p></th><th class="bottomBorder thead" scope="col" align="center" valign="bottom"><p class="docText"><span class="docEmphRoman">Solaris 9</span></p></th></tr></thead><tr><td class="rightBorder" align="left" valign="top"><p class="docText">The maximum value of any semaphore</p></td><TD class="rightBorder" align="right" valign="top"><p class="docText">32,767</P></td><TD class="rightBorder" align="right" valign="top"><p class="docText">32,767</P></TD><td class="rightBorder" align="right" valign="top"><p class="docText">32,767</P></TD><TD class="docTableCell" align="right" valign="top"><p class="docText">32,767</p></TD></tr><TR><TD class="rightBorder" align="left" valign="top"><p class="docText">The maximum value of any semaphore's adjust-on-exit value</P></td><TD class="rightBorder" align="right" valign="top"><p class="docText">16,384</P></td><TD class="rightBorder" align="right" valign="top"><p class="docText">32,767</P></td><td class="rightBorder" align="right" valign="top"><p class="docText">16,384</p></td><TD class="docTableCell" align="right" valign="top"><p class="docText">16,384</p></TD></tr><TR><td class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of semaphore sets, systemwide</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">10</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">128</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">87,381</p></td><td class="docTableCell" align="right" valign="top"><p class="docText">10</p></td></tr><tr><TD class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of semaphores, systemwide</P></td><TD class="rightBorder" align="right" valign="top"><p class="docText">60</P></TD><td class="rightBorder" align="right" valign="top"><p class="docText">32,000</P></TD><TD class="rightBorder" align="right" valign="top"><p class="docText">87,381</p></TD><td class="docTableCell" align="right" valign="top"><p class="docText">60</P></TD></TR><tr><TD class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of semaphores per semaphore set</P></td><TD class="rightBorder" align="right" valign="top"><p class="docText">60</P></td><td class="rightBorder" align="right" valign="top"><p class="docText">250</p></td><TD class="rightBorder" align="right" valign="top"><p class="docText">87,381</p></TD><td class="docTableCell" align="right" valign="top"><p class="docText">25</P></td></tr><tr><td class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of undo structures, systemwide</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">30</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">32,000</p></td><td class="rightBorder" align="right" valign="top"><p class="docText">87,381</p></td><td class="docTableCell" align="right" valign="top"><p class="docText">30</p></TD></TR><tr><TD class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of undo entries per undo structures</P></TD><td class="rightBorder" align="right" valign="top"><p class="docText">10</P></TD><TD class="rightBorder" align="right" valign="top"><p class="docText">32</p></TD><td class="rightBorder" align="right" valign="top"><p class="docText">10</P></TD><TD class="docTableCell" align="right" valign="top"><p class="docText">10</p></TD></TR><tr><TD class="rightBorder" align="left" valign="top"><p class="docText">The maximum number of operations per <tt>semop</tt> call</P></td><td class="rightBorder" align="right" valign="top"><p class="docText">100</p></td><TD class="rightBorder" align="right" valign="top"><p class="docText">32</p></TD><td class="rightBorder" align="right" valign="top"><p class="docText">100</P></td><td class="docTableCell" align="right" valign="top"><p class="docText">10</p></td></tr></table></p><br>
<p class="docText">The first function to call is <tt>semget</tt> to obtain a semaphore ID.</p>
<a name="inta278"></a><p><table cellspacing="0" class="allBorders" border="1" RULES="none" cellpadding="5"><colgroup><col width="500"></colgroup><thead></thead><tr><td class="docTableCell" align="left" valign="top"><p class="docText">
<pre>
#include &lt;sys/sem.h&gt;

int semget(key_t <span class="docEmphItalicAlt">key</span>, int <span class="docEmphItalicAlt">nsems</span>, int <span class="docEmphItalicAlt">flag</span>);
</pre><br>

</p></td></tr><tr><td class="docTableCell" align="right" valign="top"><p class="docText">Returns: semaphore ID if OK, 1 on error</P></TD></tr></table></P><BR>
<p class="docText">In <a class="docLink" href="ch15lev1sec6.html#ch15lev2sec1">Section 15.6.1</a>, we described the rules for converting the <span class="docEmphasis">key</span> into an identifier and discussed whether a new set is created or an existing set is referenced. When a new set is created, the following members of the <tt>semid_ds</tt> structure are initialized.</P>
<ul><LI><p class="docList">The <tt>ipc_perm</tt> structure is initialized as described in <a class="docLink" href="ch15lev1sec6.html#ch15lev2sec2">Section 15.6.2</a>. The <tt>mode</tt> member of this structure is set to the corresponding permission bits of <span class="docEmphasis">flag</span>. These permissions are specified with the values from <a class="docLink" href="ch15lev1sec6.html#ch15fig24">Figure 15.24</a>.</P></LI><li><p class="docList"><tt>sem_otime</tt> is set to 0.</P></li><LI><p class="docList"><tt>sem_ctime</tt> is set to the current time.</P></LI><li><p class="docList"><tt>sem_nsems</tt> is set to <span class="docEmphasis">nsems</span>.</P></LI></ul>
<p class="docText">The number of semaphores in the set is <span class="docEmphasis">nsems</span>. If a new set is being created (typically in the server), we must specify <span class="docEmphasis">nsems</span>. If we are referencing an existing set (a client), we can specify <span class="docEmphasis">nsems</span> as 0.</P>
<p class="docText">The <tt>semctl</tt> function is the catchall for various semaphore operations.</P>
<a name="inta279"></a><p><table cellspacing="0" class="allBorders" border="1" RULES="none" cellpadding="5"><colgroup><col width="500"></colgroup><thead></thead><tr><td class="docTableCell" align="left" valign="top"><p class="docText">
<pre>
#include &lt;sys/sem.h&gt;

int semctl(int <span class="docEmphItalicAlt">semid</span>, int <span class="docEmphItalicAlt">semnum</span>, int  <span class="docEmphItalicAlt">cmd</span>,
           ... /* union semun <span class="docEmphItalicAlt">arg</span> */);
</pre><br>

</P></td></TR><tr><TD class="docTableCell" align="right" valign="top"><p class="docText">Returns: (see following)</p></td></tr></table></p><br>
<p class="docText">The fourth argument is optional, depending on the command requested, and if present, is of type <tt>semun</tt>, a union of various command-specific arguments:</p>

<pre>
   union semun {
     int              val;    /* for SETVAL */
     struct semid_ds *buf;    /* for IPC_STAT and IPC_SET */
     unsigned short  *array;  /* for GETALL and SETALL */
   };
</pre><br>

<p class="docText"><a name="idd1e115749"></a><a name="idd1e115752"></a><a name="idd1e115757"></a><a name="idd1e115762"></a><a name="idd1e115767"></a><a name="idd1e115772"></a><a name="idd1e115777"></a><a name="idd1e115782"></a><a name="idd1e115787"></a><a name="idd1e115792"></a><a name="idd1e115797"></a><a name="idd1e115802"></a><a name="idd1e115809"></a><a name="idd1e115814"></a><a name="idd1e115819"></a>Note that the optional argument is the actual union, not a pointer to the union.</p>
<p class="docText">The <span class="docEmphasis">cmd</span> argument specifies one of the following ten commands to be performed on the set specified by <span class="docEmphasis">semid</span>. The five commands that refer to one particular semaphore value use <span class="docEmphasis">semnum</span> to specify one member of the set. The value of <span class="docEmphasis">semnum</span> is between 0 and <span class="docEmphasis">nsems</span>-<span class="docEmphasis">1</span>, inclusive.</p>
<p><table cellspacing="0" FRAME="void" RULES="none" cellpadding="5"><colgroup><col width="75"><col width="425"></colgroup><thead></thead><tr><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>IPC_STAT</tt></p></td><td class="docTableCell" align="left" valign="top"><p class="docText">Fetch the <tt>semid_ds</tt> structure for this set, storing it in the structure pointed to by <span class="docEmphasis">arg.buf</span>.</p></td></TR><TR><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>IPC_SET</tt></P></TD><TD class="docTableCell" align="left" valign="top"><p class="docText">Set the <tt>sem_perm.uid</tt>, <tt>sem_perm.gid</tt>, and <tt>sem_perm.mode</tt> fields from the structure pointed to by <span class="docEmphasis">arg.buf</span> in the <tt>semid_ds</tt> structure associated with this set. This command can be executed only by a process whose effective user ID equals <tt>sem_perm.cuid</tt> or <tt>sem_perm.uid</tt> or by a process with superuser privileges.</p></TD></TR><TR><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>IPC_RMID</tt></P></td><TD class="docTableCell" align="left" valign="top"><p class="docText">Remove the semaphore set from the system. This removal is immediate. Any other process still using the semaphore will get an error of <tt>EIDRM</tt> on its next attempted operation on the semaphore. This command can be executed only by a process whose effective user ID equals <tt>sem_perm.cuid</tt> or <tt>sem_perm.uid</tt> or by a process with superuser privileges.</P></TD></tr><TR><TD class="docTableCell" align="left" valign="top"><p class="docText"><tt>GETVAL</tt></p></TD><TD class="docTableCell" align="left" valign="top"><p class="docText">Return the value of <tt>semval</tt> for the member <span class="docEmphasis">semnum</span>.</p></td></tr><tr><TD class="docTableCell" align="left" valign="top"><p class="docText"><tt>SETVAL</tt></p></TD><td class="docTableCell" align="left" valign="top"><p class="docText">Set the value of <tt>semval</tt> for the member <span class="docEmphasis">semnum</span>. The value is specified by <span class="docEmphasis">arg.val</span>.</P></td></tr><tr><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>GETPID</tt></p></td><td class="docTableCell" align="left" valign="top"><p class="docText">Return the value of <tt>sempid</tt> for the member <span class="docEmphasis">semnum</span>.</p></td></tr><tr><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>GETNCNT</tt></p></td><td class="docTableCell" align="left" valign="top"><p class="docText">Return the value of <tt>semncnt</tt> for the member <span class="docEmphasis">semnum</span>.</p></td></TR><TR><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>GETZCNT</tt></P></TD><TD class="docTableCell" align="left" valign="top"><p class="docText">Return the value of <tt>semzcnt</tt> for the member <span class="docEmphasis">semnum</span>.</p></TD></TR><TR><td class="docTableCell" align="left" valign="top"><p class="docText"><tt>GETALL</tt></P></td><TD class="docTableCell" align="left" valign="top"><p class="docText">Fetch all the semaphore values in the set. These values are stored in the array pointed to by <span class="docEmphasis">arg.array</span>.</P></TD></tr><TR><TD class="docTableCell" align="left" valign="top"><p class="docText"><tt>SETALL</tt></p></TD><TD class="docTableCell" align="left" valign="top"><p class="docText">Set all the semaphore values in the set to the values pointed to by <span class="docEmphasis">arg.array</span>.</p></td></tr></table></p><BR>
<p class="docText">For all the <tt>GET</tt> commands other than <tt>GETALL</tt>, the function returns the corresponding value. For the remaining commands, the return value is 0.</p>
<p class="docText">The function <tt>semop</tt> atomically performs an array of operations on a semaphore set.</P>
<a name="inta280"></a><p><table cellspacing="0" class="allBorders" border="1" RULES="none" cellpadding="5"><colgroup><col width="550"></colgroup><thead></thead><TR><td class="docTableCell" align="left" valign="top"><p class="docText">
<a name="PLID5"></a><div class="v1"><a href="ch15lev1sec8.html#PLID5">[View full width]</a></div><pre>
#include &lt;sys/sem.h&gt;

int semop(int <span class="docEmphItalicAlt">semid</span>, struct sembuf <span class="docEmphItalicAlt">semoparray</span>[],
<img border="0" width="14" height="9" alt="" align="left" src="images/ccc.gif"> size_t <span class="docEmphItalicAlt">nops</span>);
</pre><br>

</p></td></tr><tr><td class="docTableCell" align="right" valign="top"><p class="docText">Returns: 0 if OK, 1 on error</p></td></tr></table></p><br>
<p class="docText"><a name="idd1e116108"></a><a name="idd1e116113"></a><a name="idd1e116118"></a><a name="idd1e116123"></a>The <span class="docEmphasis">semoparray</span> argument is a pointer to an array of semaphore operations, represented by <tt>sembuf</tt> structures:</p>

<pre>
 struct sembuf {
   unsigned short  sem_num;  /* member # in set (0, 1, ..., nsems-1) */
   short           sem_op;   /* operation (negative, 0, or positive) */
   short           sem_flg;  /* IPC_NOWAIT, SEM_UNDO */
 };
</pre><br>

<p class="docText">The <span class="docEmphasis">nops</span> argument specifies the number of operations (elements) in the array.</p>
<p class="docText">The operation on each member of the set is specified by the corresponding <tt>sem_op</tt> value. This value can be negative, 0, or positive. (In the following discussion, we refer to the &quot;undo&quot; flag for a semaphore. This flag corresponds to the <tt>SEM_UNDO</tt> bit in the corresponding <tt>sem_flg</tt> member.)</p>
<div style="font-weight:bold"><ol class="docList" type="1"><li><div style="font-weight:normal"><p class="docList">The easiest case is when <tt>sem_op</tt> is positive. This case corresponds to the returning of resources by the process. The value of <tt>sem_op</tt> is added to the semaphore's value. If the undo flag is specified, <tt>sem_op</tt> is also subtracted from the semaphore's adjustment value for this process.</P></div></LI><li><div style="font-weight:normal"><p class="docList">If <tt>sem_op</tt> is negative, we want to obtain resources that the semaphore controls.</P><p class="docList">If the semaphore's value is greater than or equal to the absolute value of <tt>sem_op</tt> (the resources are available), the absolute value of <tt>sem_op</tt> is subtracted from the semaphore's value. This guarantees that the resulting value for the semaphore is greater than or equal to 0. If the undo flag is specified, the absolute value of <tt>sem_op</tt> is also added to the semaphore's adjustment value for this process.</P><p class="docList">If the semaphore's value is less than the absolute value of <tt>sem_op</tt> (the resources are not available), the following conditions apply.</P><div style="font-weight:bold"><ol class="docList" type="a"><li><div style="font-weight:normal"><p class="docList">If <tt>IPC_NOWAIT</tt> is specified, <tt>semop</tt> returns with an error of <tt>EAGAIN</tt>.</P></div></LI><LI><div style="font-weight:normal"><p class="docList">If <tt>IPC_NOWAIT</tt> is not specified, the <tt>semncnt</tt> value for this semaphore is incremented (since the caller is about to go to sleep), and the calling process is suspended until one of the following occurs.</p><div style="font-weight:bold"><ol class="docList" type="i"><LI><div style="font-weight:normal"><p class="docList">The semaphore's value becomes greater than or equal to the absolute value of <tt>sem_op</tt> (i.e., some other process has released some resources). The value of <tt>semncnt</tt> for this semaphore is decremented (since the calling process is done waiting), and the absolute value of <tt>sem_op</tt> is subtracted from the semaphore's value. If the undo flag is specified, the absolute value of <tt>sem_op</tt> is also added to the semaphore's adjustment value for this process.</p></div></LI><LI><div style="font-weight:normal"><p class="docList">The semaphore is removed from the system. In this case, the function returns an error of <tt>EIDRM</tt>.</P></div></li><LI><div style="font-weight:normal"><p class="docList">A signal is caught by the process, and the signal handler returns. In this case, the value of <tt>semncnt</tt> for this semaphore is decremented (since the <a name="idd1e116258"></a><a name="idd1e116261"></a><a name="idd1e116264"></a><a name="idd1e116269"></a><a name="idd1e116274"></a><a name="idd1e116279"></a><a name="idd1e116284"></a>calling process is no longer waiting), and the function returns an error of <tt>EINTR</tt>.</P></div></li></ol></div></div></LI></ol></div></div></LI><li><div style="font-weight:normal"><p class="docList">If <tt>sem_op</tt> is 0, this means that the calling process wants to wait until the semaphore's value becomes 0.</p><p class="docList">If the semaphore's value is currently 0, the function returns immediately.</p><p class="docList">If the semaphore's value is nonzero, the following conditions apply.</p><div style="font-weight:bold"><ol class="docList" type="a"><LI><div style="font-weight:normal"><p class="docList">If <tt>IPC_NOWAIT</tt> is specified, return is made with an error of <tt>EAGAIN</tt>.</p></div></LI><li><div style="font-weight:normal"><p class="docList">If <tt>IPC_NOWAIT</tt> is not specified, the <tt>semzcnt</tt> value for this semaphore is incremented (since the caller is about to go to sleep), and the calling process is suspended until one of the following occurs.</P><div style="font-weight:bold"><ol class="docList" type="i"><li><div style="font-weight:normal"><p class="docList">The semaphore's value becomes 0. The value of <tt>semzcnt</tt> for this semaphore is decremented (since the calling process is done waiting).</p></div></li><li><div style="font-weight:normal"><p class="docList">The semaphore is removed from the system. In this case, the function returns an error of <tt>EIDRM</tt>.</p></div></li><li><div style="font-weight:normal"><p class="docList">A signal is caught by the process, and the signal handler returns. In this case, the value of <tt>semzcnt</tt> for this semaphore is decremented (since the calling process is no longer waiting), and the function returns an error of <tt>EINTR</tt>.</p></div></li></ol></div></div></li></ol></div></div></li></ol></div>
<p class="docText">The <tt>semop</tt> function operates atomically; it does either all the operations in the array or none of them.</p>
<a name="ch15lev2sec5"></a>
<h4 class="docSection2Title">Semaphore Adjustment on <tt>exit</tt></h4>
<p class="docText">As we mentioned earlier, it is a problem if a process terminates while it has resources allocated through a semaphore. Whenever we specify the <tt>SEM_UNDO</tt> flag for a semaphore operation and we allocate resources (a <tt>sem_op</tt> value less than 0), the kernel remembers how many resources we allocated from that particular semaphore (the absolute value of <tt>sem_op</tt>). When the process terminates, either voluntarily or involuntarily, the kernel checks whether the process has any outstanding semaphore adjustments and, if so, applies the adjustment to the corresponding semaphore.</p>
<p class="docText">If we set the value of a semaphore using <tt>semctl</tt>, with either the <tt>SETVAL</tt> or <tt>SETALL</tt> commands, the adjustment value for that semaphore in all processes is set to 0.</p>
<a name="ch15ex12"></a>
<h5 class="docExampleTitle">ExampleTiming Comparison of Semaphores versus Record Locking</H5>
<p class="docText">If we are sharing a single resource among multiple processes, we can use either a semaphore or record locking. It's interesting to compare the timing differences between the two techniques.</P>
<p class="docText"><a name="idd1e116416"></a><a name="idd1e116419"></a><a name="idd1e116424"></a><a name="idd1e116429"></a><a name="idd1e116434"></a><a name="idd1e116439"></a><a name="idd1e116442"></a><a name="idd1e116445"></a><a name="idd1e116450"></a>With a semaphore, we create a semaphore set consisting of a single member and initialize the semaphore's value to 1. To allocate the resource, we call <tt>semop</tt> with a <tt>sem_op</tt> of -1; to release the resource, we perform a <tt>sem_op</tt> of +1. We also specify <tt>SEM_UNDO</tt> with each operation, to handle the case of a process that terminates without releasing its resource.</p>
<p class="docText">With record locking, we create an empty file and use the first byte of the file (which need not exist) as the lock byte. To allocate the resource, we obtain a write lock on the byte; to release it, we unlock the byte. The properties of record locking guarantee that if a process terminates while holding a lock, then the lock is automatically released by the kernel.</P>
<p class="docText"><a class="docLink" href="#ch15fig29">Figure 15.29</a> shows the time required to perform these two locking techniques on Linux. In each case, the resource was allocated and then released 100,000 times. This was done simultaneously by three different processes. The times in <a class="docLink" href="#ch15fig29">Figure 15.29</a> are the totals in seconds for all three processes.</P>
<p class="docText">On Linux, there is about a 60 percent penalty in the elapsed time for record locking compared to semaphore locking.</P>
<p class="docText">Even though record locking is slower than semaphore locking, if we're locking a single resource (such as a shared memory segment) and don't need all the fancy features of XSI semaphores, record locking is preferred. The reasons are that it is much simpler to use, and the system takes care of any lingering locks when a process terminates.</p>

<a name="ch15fig29"></a><P><table cellspacing="0" class="allBorders" border="1" RULES="groups" cellpadding="5"><caption><H5 class="docTableTitle">Figure 15.29. Timing comparison of locking alternatives on Linux</H5></caption><colgroup><col width="150"><col width="50"><col width="50"><col width="50"></colgroup><thead><tr><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="top"><p class="docText"><span class="docEmphRoman">Operation</span></P></th><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="top"><p class="docText"><span class="docEmphRoman">User</span></p></th><th class="rightBorder bottomBorder thead" scope="col" align="center" valign="top"><p class="docText"><span class="docEmphRoman">System</span></P></th><th class="bottomBorder thead" scope="col" align="center" valign="top"><p class="docText"><span class="docEmphRoman">Clock</span></P></th></TR></thead><tr><TD class="rightBorder" align="left" valign="top"><p class="docText">semaphores with undo</P></td><TD class="rightBorder" align="center" valign="top"><p class="docText">0.38</P></td><td class="rightBorder" align="center" valign="top"><p class="docText">0.48</p></td><TD class="docTableCell" align="center" valign="top"><p class="docText">0.86</p></TD></tr><TR><td class="rightBorder" align="left" valign="top"><p class="docText">advisory record locking</p></td><td class="rightBorder" align="center" valign="top"><p class="docText">0.41</p></td><td class="rightBorder" align="center" valign="top"><p class="docText">0.95</p></td><td class="docTableCell" align="center" valign="top"><p class="docText">1.36</p></td></tr></table></p><br>


<a href="17021535.html"><img src="images/pixel.gif" alt="" width="1" height="1" border="0"></a><ul></ul></TD></TR></table>
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr><td><div STYLE="MARGIN-LEFT: 0.15in;"><a href="toc.html"><img src="images/team.gif" width="60" height="17" border="0" align="absmiddle"  alt="Team BBL"></a></div></td>
<td align="right"><div STYLE="MARGIN-LEFT: 0.15in;">
<a href=ch15lev1sec7.html><img src="images/prev.gif" width="60" height="17" border="0" align="absmiddle" alt="Previous Page"></a>
<a href=ch15lev1sec9.html><img src="images/next.gif" width="60" height="17" border="0" align="absmiddle" alt="Next Page"></a>
</div></td></tr></table>
</body></html><br>
<table width="100%" cellspacing="0" cellpadding="0"
style="margin-top: 0pt; border-collapse: collapse;"> 
<tr> <td align="right" style="background-color=white; border-top: 1px solid gray;"> 
<a href="http://www.zipghost.com/" target="_blank" style="font-family: Tahoma, Verdana;
 font-size: 11px; text-decoration: none;">The CHM file was converted to HTM by Trial version of <b>ChmD<!--13-->ecompiler</b>.</a>
</TD>
</TR><tr>
<td align="right" style="background-color=white; "> 
<a href="http://www.etextwizard.com/download/cd/cdsetup.exe" target="_blank" style="font-family: Tahoma, Verdana;
 font-size: 11px; text-decoration: none;">Download <b>ChmDec<!--13-->ompiler</b> at: http://www.zipghost.com</a>
</TD></tr></table>
